#!/usr/bin/ruby -Ku
# -*- coding: utf-8-emacs -*-
require 'test/unit'
require 'm3g'

class Test_SkinnedMesh < Test::Unit::TestCase
  def setup
  end

  def teadown
  end


  def test_defualt_variables_1
    positions     = M3G::VertexArray.new 2,3,4
    vbuf          = M3G::VertexBuffer.new
    vbuf.positions= positions, 1, [0,0,0]
    indices       = [0,1,2]
    strip_lengths = [3]
    ibufs         = [(M3G::TriangleStripArray.new indices, strip_lengths),
                     (M3G::TriangleStripArray.new indices, strip_lengths)]
    apps          = [M3G::Appearance.new, M3G::Appearance.new]
    skeleton      = M3G::Group.new
    mesh          = M3G::SkinnedMesh.new vbuf, ibufs, apps, skeleton
    
    assert_equal vbuf    , mesh.vertex_buffer
    assert_equal 2       , mesh.submesh_count
    assert_equal ibufs[0], mesh.index_buffer[0]
    assert_equal ibufs[1], mesh.index_buffer[1]
    assert_equal apps[0] , mesh.appearance[0]
    assert_equal apps[1] , mesh.appearance[1]
    assert_equal skeleton, mesh.skeleton
  end

  def test_defualt_variables_2
    positions     = M3G::VertexArray.new 2,3,4
    vbuf          = M3G::VertexBuffer.new 
    vbuf.positions= positions, 1, [0,0,0]
    indices       = [0,1,2]
    strip_lengths = [3]
    ibuf          = M3G::TriangleStripArray.new indices, strip_lengths
    app           = M3G::Appearance.new
    skeleton      = M3G::Group.new
    mesh          = M3G::SkinnedMesh.new vbuf, ibuf, app, skeleton

    assert_equal vbuf, mesh.vertex_buffer
    assert_equal 1   , mesh.submesh_count
    assert_equal ibuf, mesh.index_buffer[0]
    assert_equal app , mesh.appearance[0]
    assert_equal skeleton, mesh.skeleton
  end



  def test_duplicate
    positions     = M3G::VertexArray.new 2,3,4
    vbuf          = M3G::VertexBuffer.new 
    vbuf.positions= positions, 1, [0,0,0]
    indices       = [0,1,2]
    strip_lengths = [3]
    ibuf          = M3G::TriangleStripArray.new indices, strip_lengths
    app           = M3G::Appearance.new
    skeleton      = M3G::Group.new
    mesh1         = M3G::SkinnedMesh.new vbuf, ibuf, app, skeleton

    mesh2 = mesh1.duplicate

    # 注意:duplicateされるのはmesh本体とskeleton以下。
    # meshから参照されるvbuf,ibuf,appは複製されず
    # 同じインスタンスを参照する
    assert_not_equal mesh2, mesh1
    assert_equal vbuf, mesh2.vertex_buffer
    assert_equal 1   , mesh2.submesh_count
    assert_equal ibuf, mesh2.index_buffer[0]
    assert_equal app , mesh2.appearance[0]
    assert_not_equal mesh2.skeleton, mesh1.skeleton
  end


  def test_references
    positions     = M3G::VertexArray.new 2,3,4
    vbuf          = M3G::VertexBuffer.new 
    vbuf.positions= positions, 1, [0,0,0]
    indices       = [0,1,2]
    strip_lengths = [3]
    ibuf          = M3G::TriangleStripArray.new indices, strip_lengths
    app           = M3G::Appearance.new
    skeleton      = M3G::Group.new
    mesh          = M3G::SkinnedMesh.new vbuf, ibuf, app, skeleton

    objs = mesh.references
    assert_equal 4   , objs.length
    assert_equal vbuf, objs[0]
    assert_equal ibuf, objs[1]
    assert_equal app , objs[2]
    assert_equal skeleton , objs[3]
  end

  def test_add_transform_get_bone_vertices
    positions = M3G::VertexArray.new 10, 3, 4
    vbuf      = M3G::VertexBuffer.new 
    vbuf.positions = positions, 1, [0,0,0]
    tris      = M3G::TriangleStripArray.new [0,1,2], [3]
    app       = M3G::Appearance.new

    # bone0 --> bone1 --> bone2
    #             |-----> bone3
    bone0    = M3G::Group.new
    bone1    = M3G::Group.new
    bone2    = M3G::Group.new
    bone3    = M3G::Group.new
    bone1.translate 0,1,0
    bone2.translate 1,0,0
    bone3.translate 1,0,0
    bone0.child << bone1
    bone1.child << bone2
    bone1.child << bone3
  
    mesh     = M3G::SkinnedMesh.new vbuf, tris, app, bone0

    # vertices 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
    # bone0    ----------        ----
    # bone1          ----------
    # bone2          ----                   
    # bone3                      ----------
    mesh.bone_transform << [bone0, 100, 0, 4]
    mesh.bone_transform << [bone0, 100, 6, 2]
    mesh.bone_transform << [bone1, 100, 2, 4]
    mesh.bone_transform << [bone2, 200, 2, 2]
    mesh.bone_transform << [bone3, 200, 6, 4]
  
    num, indices, weights = mesh.bone_vertices bone0

    assert_equal 6, num
    assert_equal 0, indices[0]
    assert_equal 1, indices[1]
    assert_equal 2, indices[2]
    assert_equal 3, indices[3]
    assert_equal 6, indices[4]
    assert_equal 7, indices[5]
    assert_in_delta 1         , weights[0], 0.00001
    assert_in_delta 1         , weights[1], 0.00001
    assert_in_delta 0.25      , weights[2], 0.00001
    assert_in_delta 0.25      , weights[3], 0.00001
    assert_in_delta 0.33333333, weights[4], 0.00001
    assert_in_delta 0.33333333, weights[5], 0.00001

    num, indices, weights = mesh.bone_vertices bone1

    assert_equal 4, num
    assert_equal 2, indices[0]
    assert_equal 3, indices[1]
    assert_equal 4, indices[2]
    assert_equal 5, indices[3]
    assert_in_delta 0.25     , weights[0], 0.00001
    assert_in_delta 0.25     , weights[1], 0.00001
    assert_in_delta 1        , weights[2], 0.00001
    assert_in_delta 1        , weights[3], 0.00001

    num, indices, weights = mesh.bone_vertices bone2

    assert_equal 2, num
    assert_equal 2, indices[0]
    assert_equal 3, indices[1]
    assert_in_delta 0.5     , weights[0], 0.00001
    assert_in_delta 0.5     , weights[1], 0.00001

    num, indices, weights = mesh.bone_vertices bone3

    assert_equal 4, num
    assert_equal 6, indices[0]
    assert_equal 7, indices[1]
    assert_equal 8, indices[2]
    assert_equal 9, indices[3]
    assert_in_delta 0.6666667 , weights[0], 0.00001
    assert_in_delta 0.6666667 , weights[1], 0.00001
    assert_in_delta 1         , weights[2], 0.00001
    assert_in_delta 1         , weights[3], 0.00001
  end

  def test_get_bone_transform
    varry = M3G::VertexArray.new 10, 3, 2
    vbuf  = M3G::VertexBuffer.new
    vbuf.positions = varry, 1, [0,0,0]
    tris  = M3G::TriangleStripArray.new [0,1,2], [3]
    app   = M3G::Appearance.new

    bone0    = M3G::Group.new
    bone1    = M3G::Group.new
    bone2    = M3G::Group.new
    bone1.translate 0,1,0
    bone2.translate 1,0,0
    bone0.child << bone1
    bone0.child << bone2

    mesh        = M3G::SkinnedMesh.new vbuf, tris, app, bone0

    # vertices 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
    # bone0    ----------        ----
    # bone1          ----------
    # bone2          ----                   
    mesh.bone_transform << [bone0, 100, 0, 4]
    mesh.bone_transform << [bone0, 100, 6, 2]
    mesh.bone_transform << [bone1, 100, 2, 4]
    mesh.bone_transform << [bone2, 20,  2, 2]   # ウェイトの小さな3つ目のボーンは無視

    trns = mesh.bone_transform bone1
    assert_in_delta -1, trns.matrix[7], 0.00001   # m[1][3] = ty

    trns = mesh.bone_transform bone2
    assert_in_delta -1, trns.matrix[3], 0.00001    # m[0][3] = tx
  end
end
